/****************************************************************************
 * Copyright (C) 2009-2010 SciTouch LLC
 * 
 * This file is part of Indigo toolkit.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/

#ifndef __reaction_substructure_matcher__
#define __reaction_substructure_matcher__

#include "graph/embedding_enumerator.h"
#include "molecule/molecule_arom_match.h"

class Reaction;
struct ReactionHighlighting;
class ReactionAtomNeighbourhoodCounters;

typedef RedBlackMap<int, int> RedBlackIntMap;

class ReactionSubstructureMatcher
{
public:
   ReactionSubstructureMatcher (const Reaction &target);

   void setQuery (const Reaction &query);
   void setNeiCounters (const ReactionAtomNeighbourhoodCounters *query_counters, 
      const ReactionAtomNeighbourhoodCounters *target_counters);

   bool use_aromaticity_matcher;

   ReactionHighlighting *highlighting;

   bool find ();

   DEF_ERROR("reaction substructure matcher");

protected:

   void _initMap (const Reaction &reaction, RedBlackMap<int, int> &aam_map);
   int  _checkAAM () const;
   void _highlight ();

   enum
   {
      _FIRST_SIDE,
      _SECOND_SIDE,
      _SECOND_SIDE_REST,
      _CONTINUE,
      _NO_WAY,
      _RETURN
   };

   class _Matcher
   {
   public:
      _Matcher (ReactionSubstructureMatcher &context);
      _Matcher (const _Matcher &other);

      int  nextPair ();
      void setMode (int mode) { _mode = mode; }
      int  getMode () { return _mode; }
      bool addPair (int mol1_idx, int mol2_idx, const Array<int> &core1, const Array<int> &core2, bool from_first_side);
      void restore ();

      int _current_molecule_1, _current_molecule_2;

      TL_CP_DECL(Array<int>, _current_core_1);
      TL_CP_DECL(Array<int>, _current_core_2);

   protected:
      int _nextPair ();

      static int _embedding (const Graph &subgraph, const Graph &supergraph, int *core_sub, int *core_super, void *userdata);
      static bool _matchAtoms (const Graph &subgraph, const Graph &supergraph, const int *core_sub, int sub_idx, int super_idx, void *userdata);
      static bool _matchBonds (const Graph &subgraph, const Graph &supergraph, int sub_idx, int super_idx, void *userdata);
      static void _removeAtom (const Graph &subgraph, int sub_idx, void *userdata);
      static void _addAtom (const Graph &subgraph, const Graph &supergraph, int sub_idx, int super_idx, void *userdata);
      static void _addBond (const Graph &subgraph, const Graph &supergraph, int sub_idx, int super_idx, void *userdata);

      ReactionSubstructureMatcher &_context;
      AutoPtr<AromaticityMatcher> _am;

      Obj<EmbeddingEnumerator> _enumerator; 
      int _mode;
      int _selected_molecule_1;
      int _selected_molecule_2;
      TL_CP_DECL(Array<int>, _mapped_aams);
   };

   const Reaction &_target;
   
   TL_CP_DECL(ObjArray<_Matcher>, _matchers);
   TL_CP_DECL(RedBlackIntMap, _amm_to_second_side_1);
   TL_CP_DECL(RedBlackIntMap, _amm_to_second_side_2);
   TL_CP_DECL(Array<int>, _molecule_core_1);
   TL_CP_DECL(Array<int>, _molecule_core_2);
   TL_CP_DECL(RedBlackIntMap, _amm_core_first_side);

   int _first_side;
   int _second_side;

   const Reaction *_query;

   TL_CP_DECL(ObjArray< Array<int> >, _query_h_counters);
   TL_CP_DECL(ObjArray< Array<int> >, _target_h_counters);

   const ReactionAtomNeighbourhoodCounters 
      *_query_nei_counters, *_target_nei_counters;

   AromaticityMatcher  *_am;
};


#endif
